home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Sockets / socket.tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  18.8 KB  |  872 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    A more or less BSD compatable socket library for MacTCP
  3.  *    
  4.  *    Summer 1989, Tom Milligan, University of Toronto Computing Services
  5.  */
  6.  
  7.      
  8. #include <Events.h>
  9. #include <memory.h>
  10. #include <types.h>
  11. #include <OSUtils.h> /* for SysBeep */
  12. #include <Events.h> /* for TickCount */
  13.  
  14. #include <stdio.h>
  15.  
  16. #include <sys/types.h>
  17. #include <sys/time.h>
  18. #include <sys/errno.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <sys/uio.h>
  22.  
  23. #include "tcpglue.h"
  24. #include "socket.internal.h"
  25.  
  26.  
  27. /*
  28.  * asynchronous notification routine 
  29.  */
  30. static int notified = 0;
  31. static int lastNotifyCount = 0;
  32.  
  33. static StreamPtr notifyTcpStream;
  34. static unsigned short notifyEventCode;
  35. static Ptr notifyUserDataPtr;
  36. static unsigned short notifyTerminReason;
  37. static struct ICMPReport *notifyIcmpMsg;
  38.  
  39. pascal void sock_tcp_notify(tcpStream,eventCode,userDataPtr,terminReason,icmpMsg)
  40.     StreamPtr tcpStream;
  41.     unsigned short eventCode;
  42.     Ptr userDataPtr;
  43.     unsigned short terminReason;
  44.     struct ICMPReport *icmpMsg;
  45. {
  46.     notified++;
  47.  
  48.     notifyTcpStream = tcpStream;
  49.     notifyEventCode = eventCode;
  50.     notifyUserDataPtr = userDataPtr;
  51.     notifyTerminReason = terminReason;
  52.     notifyIcmpMsg = icmpMsg;
  53. }
  54.  
  55. static char *eventNames[] = 
  56. {
  57.     "event 0",
  58.     "closing",
  59.     "ULP timeout",
  60.     "terminate",
  61.     "data arrival",
  62.     "urgent data",
  63.     "ICMP message"
  64. };
  65. static char *terminateReasons[] =
  66. {
  67.     "reason 0",
  68.     "reason 1",
  69.     "remote abort",
  70.     "network failure",
  71.     "security/precedence mismatch",
  72.     "ULP timeout",
  73.     "ULP abort",
  74.     "ULP close",
  75.     "service failure"
  76. };
  77. static char *icmpMessages[] =
  78. {
  79.     "net unreachable",
  80.     "host unreachable",
  81.     "protocol unreachable",
  82.     "port unreachable",
  83.     "fragmentation required",
  84.     "source route failed",
  85.     "time exceeded",
  86.     "parameter problem",
  87.     "missing required option"
  88. };
  89. tcpCheckNotify()
  90. {
  91.     if (notified == lastNotifyCount)
  92.         return;
  93.     
  94.     lastNotifyCount = notified;
  95.     dprintf("notify count is now %d\n",lastNotifyCount);
  96.     dprintf("stream %08x\n",notifyTcpStream);
  97.     dprintf("event %d '%s'\n",notifyEventCode,eventNames[notifyEventCode]);
  98.     if (notifyEventCode == TCPTerminate)
  99.         dprintf("reason %d '%s'\n",notifyTerminReason,terminateReasons[notifyTerminReason]);
  100.     if (notifyEventCode == TCPDataArrival)
  101.         dprintf("%d bytes\n",notifyTerminReason/*!?*/);
  102.     dprintf("icmp msg %08x\n",notifyIcmpMsg);
  103.     if (notifyEventCode == TCPICMPReceived)
  104.     {
  105.         dprintf("stream %08x\n",notifyIcmpMsg->streamPtr);
  106.         dprintf("local %08x/%d\n",notifyIcmpMsg->localHost,notifyIcmpMsg->localPort);
  107.         dprintf("remote %08x/%d\n",notifyIcmpMsg->remoteHost,notifyIcmpMsg->remotePort);
  108.         dprintf("%s\n",icmpMessages[notifyIcmpMsg->reportType]);
  109.         dprintf("optionalAddlInfo %04x\n",notifyIcmpMsg->optionalAddlInfo);
  110.         dprintf("optionalAddlInfoPtr %08x\n",notifyIcmpMsg->optionalAddlInfoPtr);
  111.     }
  112.     dprintf("userdata %s\n",notifyUserDataPtr);
  113. }
  114.  
  115. /*
  116.  * sock_tcp_new_stream
  117.  *
  118.  * Create a new tcp stream.
  119.  */
  120. sock_tcp_new_stream(sp)
  121.     SocketPtr sp;
  122. {
  123.     OSErr io;
  124.     int i;
  125.  
  126. #if SOCK_TCP_DEBUG >= 2
  127.     sock_print("sock_tcp_new_stream", sp);
  128. #endif
  129.     
  130.     io = xTCPCreate(STREAM_BUFFER_SIZE, sock_tcp_notify, &sp->pb.tcp);
  131.     switch(io)
  132.     {
  133.         case noErr:                 break;
  134.         case streamAlreadyOpen:     return(sock_err(io));
  135.         case invalidLength:         return(sock_err(ENOBUFS));
  136.         case invalidBufPtr:         return(sock_err(ENOBUFS));
  137.         case insufficientResources: return(sock_err(EMFILE));
  138.         default: /* error from PBOpen */ return(sock_err(ENETDOWN));
  139.     }
  140.     sp->sstate = SOCK_STATE_UNCONNECTED;
  141.     sp->peer.sin_family = AF_INET;
  142.     sp->peer.sin_addr.s_addr = 0;
  143.     sp->peer.sin_port = 0;
  144.     bzero(&sp->peer.sin_zero[0], 8);
  145.     sp->dataavail = 0;
  146.     sp->asyncerr = 0;
  147.  
  148.     sp->pb.tcp.ioResult = noErr;
  149.  
  150.     sp->apb.pb.tcp.tcpStream = sp->pb.tcp.tcpStream;
  151.     sp->apb.pb.tcp.ioResult = noErr;
  152.  
  153.     for (i=0; i<TCP_MAX_WRITES; i++)
  154.     {
  155.         sp->wpb[i].pb.tcp.tcpStream = sp->pb.tcp.tcpStream;
  156.         sp->wpb[i].pb.tcp.ioResult = noErr;
  157.     }
  158.     sp->nextwpb = 0;
  159.  
  160.     return(0);
  161. }
  162.  
  163.  
  164. /*
  165.  *    sock_tcp_connect - initiate a connection on a TCP socket
  166.  *
  167.  */
  168. sock_tcp_connect(sp, addr)
  169.     SocketPtr sp;
  170.     struct sockaddr_in *addr;
  171. {
  172.     OSErr io;
  173.     void sock_tcp_connect_done();
  174.     
  175. #if SOCK_TCP_DEBUG >= 2
  176.     sock_print("sock_tcp_connect",sp);
  177. #endif
  178.     
  179.     /* Make sure this socket can connect. */
  180.     if (sp->sstate == SOCK_STATE_CONNECTING)
  181.         return(sock_err(EALREADY));
  182.     if (sp->sstate != SOCK_STATE_UNCONNECTED)
  183.         return(sock_err(EISCONN));
  184.         
  185.     sp->sstate = SOCK_STATE_CONNECTING;
  186.     io = xTCPActiveOpen(&sp->apb.pb.tcp, sp->sa.sin_port,
  187.                 addr->sin_addr.s_addr, addr->sin_port, 
  188.                 sock_tcp_connect_done);
  189.     if (io != noErr)
  190.     {
  191.         sp->sstate = SOCK_STATE_UNCONNECTED;
  192.         return(sock_err(io));
  193.     }
  194.     
  195.     if (sp->nonblocking)        
  196.         return(sock_err(EINPROGRESS));
  197.     
  198.     /* sync connect - spin till TCPActiveOpen completes */
  199. #if SOCK_TCP_DEBUG >= 5
  200.     dprintf("spinning in connect\n");
  201. #endif
  202.     while(sp->sstate == SOCK_STATE_CONNECTING)
  203.     {
  204. #if SOCK_TCP_DEBUG >= 5
  205.         tcpCheckNotify();
  206. #endif
  207.         if (spinroutine != NULL)
  208.             (*spinroutine)();
  209.     }
  210. #if SOCK_TCP_DEBUG >= 5
  211.     dprintf("done spinning\n");
  212. #endif
  213.     
  214.     if (sp->asyncerr != 0)
  215.     {
  216.         (void) sock_err(sp->asyncerr);
  217.         sp->asyncerr = 0;
  218.         return(-1);
  219.     }
  220.     return(0);
  221. }
  222.  
  223. static void
  224. sock_tcp_connect_done(apb)
  225.     async_pb *apb;
  226. {
  227.     SocketPtr sp = apb->sp;
  228.  
  229.     switch(apb->pb.tcp.ioResult)
  230.     {
  231.         case noErr:
  232.             sp->asyncerr = 0;
  233.             break;
  234.         case invalidStreamPtr:
  235.             sp->asyncerr = EBADF;
  236.             break;
  237.         case connectionExists:
  238.         case duplicateSocket:
  239.             sp->asyncerr = EISCONN;
  240.             break;
  241.         case openFailed:
  242.         case ipDestDeadErr:
  243.         case ipRouteErr:
  244.             sp->asyncerr = EHOSTUNREACH;
  245.             break;
  246.         case ipNoFragMemErr:
  247.         case ipDontFragErr:
  248.         default:
  249.             sp->asyncerr = apb->pb.tcp.ioResult;    
  250.             break;
  251.     }
  252.     if (sp->asyncerr != 0) 
  253.     {
  254.         sp->sstate = SOCK_STATE_UNCONNECTED;
  255.         return;
  256.     }
  257.     sp->sa.sin_addr.s_addr = apb->pb.tcp.csParam.open.localHost;
  258.     sp->sa.sin_port = apb->pb.tcp.csParam.open.localPort;
  259.     sp->peer.sin_addr.s_addr = apb->pb.tcp.csParam.open.remoteHost;
  260.     sp->peer.sin_port = apb->pb.tcp.csParam.open.remotePort;
  261.     sp->sstate = SOCK_STATE_CONNECTED;
  262. }
  263.  
  264. /*
  265.  * sock_tcp_listen() - put s into the listen state.
  266.  */
  267. sock_tcp_listen(sp)
  268.     SocketPtr sp;
  269. {
  270.     OSErr io;
  271.     void sock_tcp_listen_done(TCPiopb *pb);
  272.  
  273. #if SOCK_TCP_DEBUG >= 2
  274.     sock_print("sock_tcp_listen",sp);
  275. #endif
  276.  
  277.     if (sp->sstate != SOCK_STATE_UNCONNECTED)
  278.         return(sock_err(EISCONN));
  279.     
  280.     sp->sstate = SOCK_STATE_LISTENING;
  281.     io = xTCPPassiveOpen(&sp->apb.pb.tcp, sp->sa.sin_port, sock_tcp_listen_done);
  282.     if (io != noErr) 
  283.     {
  284.         sp->sstate = SOCK_STATE_UNCONNECTED;
  285.         return(sock_err(io));
  286.     }
  287. #if SOCK_TCP_DEBUG >= 5
  288.     dprintf("sock_tcp_listen: about to spin for port number - ticks %d\n",
  289.             TickCount());
  290. #endif
  291.     while (sp->apb.pb.tcp.csParam.open.localPort == 0)
  292.     {
  293. #if SOCK_TCP_DEBUG >= 5
  294.         tcpCheckNotify();
  295. #endif
  296.         if (spinroutine != NULL)
  297.             (*spinroutine)();
  298.     }
  299. #if SOCK_TCP_DEBUG >= 5
  300.     dprintf("sock_tcp_listen: port number is %d ticks %d\n",
  301.     sp->apb.pb.tcp.csParam.open.localPort,TickCount());
  302. #endif
  303.     sp->sa.sin_addr.s_addr = sp->apb.pb.tcp.csParam.open.localHost;
  304.     sp->sa.sin_port = sp->apb.pb.tcp.csParam.open.localPort;
  305.     return(0);
  306. }
  307.  
  308. static void
  309. sock_tcp_listen_done(TCPiopb *pb)
  310. {    
  311.     OSErr io;
  312.     async_pb *apb = (async_pb *)pb;
  313.     SocketPtr sp = apb->sp;
  314.  
  315.     switch(apb->pb.tcp.ioResult)
  316.     {
  317.         case noErr:
  318. #if 0
  319.             sp->sa.sin_addr.s_addr = apb->pb.tcp.csParam.open.localHost;
  320.             sp->sa.sin_port = apb->pb.tcp.csParam.open.localPort;
  321. #endif
  322.             sp->peer.sin_addr.s_addr = apb->pb.tcp.csParam.open.remoteHost;
  323.             sp->peer.sin_port = apb->pb.tcp.csParam.open.remotePort;
  324.             sp->sstate = SOCK_STATE_LIS_CON;
  325.             sp->asyncerr = 0;
  326.             break;
  327.         case openFailed:
  328.             /* restart listen mode - don't know why we get this anyway */
  329.             io = xTCPPassiveOpen(&apb->pb.tcp, sp->sa.sin_port, sock_tcp_listen_done);
  330.             if (io != noErr) 
  331.             {
  332.                 sp->sstate = SOCK_STATE_UNCONNECTED;
  333.                 sp->asyncerr = io;
  334.             }
  335.             break;
  336.         case invalidStreamPtr:
  337.         case connectionExists:
  338.         case duplicateSocket:
  339.         case commandTimeout:
  340.         default:                
  341.             sp->sstate = SOCK_STATE_UNCONNECTED;
  342.             sp->asyncerr = apb->pb.tcp.ioResult;
  343.             break;
  344.     }
  345. }
  346.  
  347. /*
  348.  *    sock_tcp_accept()
  349.  */
  350. sock_tcp_accept(sp, from, fromlen)
  351.     SocketPtr sp;
  352.     struct sockaddr_in *from;
  353.     int *fromlen;
  354. {
  355.     int s1;
  356.  
  357. #if SOCK_TCP_DEBUG >= 2
  358.     sock_print("sock_tcp_accept",sp);
  359. #endif
  360.  
  361.     if (sp->sstate == SOCK_STATE_UNCONNECTED)
  362.     {
  363.         if (sp->asyncerr != 0)
  364.         {
  365.             (void) sock_err(sp->asyncerr);
  366.             sp->asyncerr = 0;
  367.             return(-1);
  368.         }
  369.         else
  370.             return(sock_err(ENOTCONN));
  371.     }
  372.     if (sp->sstate != SOCK_STATE_LISTENING && sp->sstate != SOCK_STATE_LIS_CON)
  373.         return(sock_err(ENOTCONN));
  374.  
  375.     if (sp->sstate == SOCK_STATE_LISTENING) 
  376.     {    
  377.         if (sp->nonblocking) 
  378.             return(sock_err(EWOULDBLOCK));
  379.  
  380.         /*    Spin till sock_tcp_listen_done runs. */
  381. #if SOCK_TCP_DEBUG >= 5
  382.         dprintf("--- blocking...\n");
  383. #endif
  384.         while(sp->sstate == SOCK_STATE_LISTENING) 
  385.         {
  386. #if SOCK_TCP_DEBUG >= 5
  387.             tcpCheckNotify();
  388. #endif
  389.             if (spinroutine != NULL)
  390.                 (*spinroutine)();
  391.         }
  392. #if SOCK_TCP_DEBUG >= 5
  393.         dprintf("--- done blocking...\n");
  394. #endif
  395.         
  396.         /* got notification - was it success? */
  397.         if (sp->sstate != SOCK_STATE_LIS_CON) 
  398.         {
  399. #if    SOCK_TCP_DEBUG >=3
  400.             dprintf("--- failed state %04x code %d\n",sp->sstate,sp->asyncerr);
  401. #endif
  402.             (void) sock_err(sp->asyncerr);
  403.             sp->asyncerr = 0;
  404.             return(-1);
  405.         }
  406.     }
  407. #if SOCK_TCP_DEBUG >= 3
  408.     dprintf("sock_tcp_accept: Have connection, peer is %08x/%d, duplicating socket.\n",
  409.             sp->peer.sin_addr,sp->peer.sin_port);
  410. #endif
  411.     /*
  412.      * Have connection.  Duplicate this socket.  The client gets the connection
  413.      * on the new socket and I create a new stream on the old socket and put it 
  414.      * in listen state. 
  415.      */
  416.     sp->sstate = SOCK_STATE_CONNECTED;
  417.  
  418.     s1 = sock_free_fd(0);
  419.     if (s1 < 0) 
  420.     {
  421.         /*    No descriptors left.  Abort the incoming connection. */
  422. #if SOCK_TCP_DEBUG >= 2
  423.         dprintf("sock_tcp_accept: No descriptors left.\n");
  424. #endif
  425.         (void) xTCPAbort(&sp->pb.tcp);
  426.         sp->sstate = SOCK_STATE_UNCONNECTED;
  427.  
  428.         /* try and put the socket back in listen mode */
  429.         if (sock_tcp_listen(sp) < 0) 
  430.         {
  431. #if SOCK_TCP_DEBUG >= 1
  432.             dprintf("sock_tcp_accept: sock_tcp_listen fails\n");
  433. #endif
  434.             sp->sstate = SOCK_STATE_UNCONNECTED;
  435.             return(-1);        /* errno already set */
  436.         }
  437.         return(sock_err(EMFILE));
  438.     }
  439.     
  440.     /* copy the incoming connection to the new socket */
  441.     sock_dup_fd(sp->fd,s1);
  442. #if SOCK_TCP_DEBUG >= 3
  443.     dprintf("sock_tcp_accept: new socket is %d\n",s1);
  444.     sock_dump();
  445. #endif
  446.  
  447.     /* Create a new MacTCP stream on the old socket and put it into */
  448.     /* listen state to accept more connections. */
  449.     if (sock_tcp_new_stream(sp) < 0 || sock_tcp_listen(sp) < 0) 
  450.     {
  451. #if SOCK_TCP_DEBUG >= 2
  452.         dprintf("accept: failed to restart old socket\n");
  453. #endif
  454.         /* nothing to listen on */
  455.         sp->sstate = SOCK_STATE_UNCONNECTED;
  456.         
  457.         /* kill the incoming connection */
  458.         xTCPRelease(&sockets[s1].pb.tcp);
  459.         sock_clear_fd(s1);
  460.         
  461.         return(-1); /* errno set */
  462.     }
  463. #if SOCK_TCP_DEBUG >= 3
  464.     dprintf("sock_tcp_accept: got new stream\n");
  465.     sock_dump();
  466. #endif
  467.  
  468.     /* return address of partner */
  469.     sock_copy_addr(&sockets[s1].peer, from, *fromlen);
  470.  
  471.     return(s1);
  472. }
  473.  
  474. /*
  475.  * sock_tcp_recv()
  476.  *
  477.  * returns bytes received or -1 and errno
  478.  */
  479. sock_tcp_recv(sp, buffer, buflen, flags)
  480.     SocketPtr sp;
  481.     char *buffer;
  482.     int buflen;    
  483.     int flags;
  484. {
  485. #pragma unused(flags)
  486.     OSErr io;
  487.     
  488. #if SOCK_TCP_DEBUG >= 2
  489.     sock_print("sock_tcp_recv",sp);
  490. #endif
  491.  
  492.     /* socket hasn't finished connecting yet */
  493.     if (sp->sstate == SOCK_STATE_CONNECTING)
  494.     {
  495. #if SOCK_TCP_DEBUG >= 5
  496.         dprintf("sock_tcp_recv: connection still in progress\n");
  497. #endif
  498.         if (sp->nonblocking)
  499.             return(sock_err(EWOULDBLOCK));
  500.             
  501.         /* async connect and sync recv? */
  502. #if SOCK_TCP_DEBUG >= 5
  503.         dprintf("sock_tcp_recv: spinning on connect\n");
  504. #endif
  505.         while(sp->sstate == SOCK_STATE_CONNECTING)
  506.         {
  507. #if SOCK_TCP_DEBUG >= 5
  508.             tcpCheckNotify();
  509. #endif
  510.             if (spinroutine != NULL)
  511.                 (*spinroutine)();
  512.         }
  513. #if SOCK_TCP_DEBUG >= 5
  514.         dprintf("sock_tcp_recv: done spinning\n");
  515. #endif
  516.     }
  517.         
  518.     /* socket is not connected */
  519.     if (! (sp->sstate == SOCK_STATE_CONNECTED)) 
  520.     {
  521.         /* see if the connect died (pretty poor test) */
  522.         if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
  523.         {
  524.             (void) sock_err(sp->asyncerr);
  525.             sp->asyncerr = 0;
  526.             return(-1);
  527.         }
  528.  
  529.         /* I guess he just forgot */
  530.         return(sock_err(ENOTCONN));        
  531.     }
  532.     
  533.     if (sp->dataavail == 0)
  534.         sp->dataavail = xTCPBytesUnread(&sp->apb.pb.tcp);
  535. #if SOCK_TCP_DEBUG >= 3
  536.     dprintf("sock_tcp_recv: %d bytes available\n", sp->dataavail);
  537. #endif
  538.     if (sp->nonblocking && sp->dataavail == 0) 
  539.             return(sock_err(EWOULDBLOCK));
  540.  
  541.     io = xTCPRcv(&sp->apb.pb.tcp, buffer, buflen, (TCPIOCompletionProc)-1);
  542.     if (io != noErr) 
  543.         return(sock_err(io));
  544. #if SOCK_TCP_DEBUG >= 5
  545.     dprintf("sock_tcp_recv: about to spin on xTCPRcv\n");
  546. #endif
  547.     while(sp->apb.pb.tcp.ioResult == inProgress)
  548.     {
  549. #if SOCK_TCP_DEBUG >= 5
  550.         tcpCheckNotify();
  551. #endif
  552.         if (spinroutine != NULL)
  553.             (*spinroutine)();
  554.     }
  555. #if SOCK_TCP_DEBUG >= 5
  556.     dprintf("sock_tcp_recv: spin done\n");
  557. #endif
  558.  
  559.     switch(sp->apb.pb.tcp.ioResult)
  560.     {
  561.         case noErr:
  562.         {
  563.             int bytesRead = sp->apb.pb.tcp.csParam.receive.rcvBuffLen;
  564. #if SOCK_TCP_DEBUG >= 3
  565.             dprintf("sock_tcp_recv: got %d bytes\n", bytesRead);
  566. #endif
  567. #if (SOCK_TCP_DEBUG >= 7) || defined(TCP_PACKET_TRACE)
  568.  
  569. #ifdef 0
  570.             hex_dump(buffer, bytesRead,
  571.             "tcp from %08x/%d\n",
  572.             sp->peer.sin_addr.s_addr,
  573.             sp->peer.sin_port);
  574. #endif
  575.  
  576. #endif
  577.             if (sp->dataavail > bytesRead)
  578.                 sp->dataavail -= bytesRead;
  579.             else
  580.                 sp->dataavail = 0;
  581.             return(bytesRead);
  582.         }
  583.         case connectionClosing:
  584.             /* The connection is closed with all data delivered */
  585. #if SOCK_TCP_DEBUG >= 2
  586.             dprintf("sock_tcp_recv: connection closed\n");
  587. #endif
  588.             return(0);
  589.  
  590.         case connectionTerminated:
  591.             /* The connection is aborted. */
  592.             sp->sstate = SOCK_STATE_UNCONNECTED;
  593. #if SOCK_TCP_DEBUG >= 1
  594.             dprintf("sock_tcp_recv: connection gone!\n");
  595. #endif
  596.             return(sock_err(ENOTCONN));
  597.  
  598.         case commandTimeout:
  599.         case connectionDoesntExist:
  600.         case invalidStreamPtr:
  601.         case invalidLength:
  602.         case invalidBufPtr:
  603.         default:
  604.             return(sock_err(sp->apb.pb.tcp.ioResult));
  605.     }
  606. }
  607.  
  608.  
  609. /*
  610.  *    sock_tcp_can_read() - returns non-zero if data or a connection is available
  611.  */
  612. sock_tcp_can_read(sp)
  613.     SocketPtr sp;
  614. {
  615.     if (sp->sstate == SOCK_STATE_LIS_CON) 
  616.         return(1);
  617.  
  618.     if (sp->sstate == SOCK_STATE_CONNECTED) 
  619.     {
  620.         sp->dataavail = xTCPBytesUnread(&sp->apb.pb.tcp);
  621.         if (sp->dataavail > 0) 
  622.             return(1);
  623.     }
  624.  
  625.     return(0);
  626. }
  627.  
  628.  
  629. /*
  630.  *    sock_tcp_send() - send the data in the (already prepared) wds
  631.  *
  632.  *    returns bytes sent or -1 and errno
  633.  */
  634. sock_tcp_send(sp, buffer, count, vector, flags/*ignored*/)
  635.     SocketPtr sp;
  636.     char *buffer;
  637.     int count;
  638.     Boolean vector;
  639.     int flags;
  640. {
  641. #pragma unused(flags)
  642.     OSErr io;
  643.     void sock_tcp_send_done();
  644.     int bytes;
  645.  
  646. #if SOCK_TCP_DEBUG >= 2
  647.     sock_print("sock_tcp_send",sp);
  648. #endif
  649.  
  650.     /* socket hasn't finished connecting yet */
  651.     if (sp->sstate == SOCK_STATE_CONNECTING)
  652.     {
  653. #if SOCK_TCP_DEBUG >= 5
  654.         dprintf("sock_tcp_send: connection still in progress\n");
  655. #endif
  656.         if (sp->nonblocking)
  657.             return(sock_err(EALREADY));
  658.             
  659.         /* async connect and sync send? */
  660. #if SOCK_TCP_DEBUG >= 5
  661.         dprintf("sock_tcp_send: spinning on connect\n");
  662. #endif
  663.         while(sp->sstate == SOCK_STATE_CONNECTING)
  664.         {
  665. #if SOCK_TCP_DEBUG >= 5
  666.             tcpCheckNotify();
  667. #endif
  668.             if (spinroutine != NULL)
  669.                 (*spinroutine)();
  670.         }
  671. #if SOCK_TCP_DEBUG >= 5
  672.         dprintf("sock_tcp_send: done spinning\n");
  673. #endif
  674.     }
  675.         
  676.     /* socket is not connected */
  677.     if (! (sp->sstate == SOCK_STATE_CONNECTED)) 
  678.     {
  679.         /* see if a previous operation failed */
  680.         if (sp->sstate == SOCK_STATE_UNCONNECTED && sp->asyncerr != 0)
  681.         {
  682.             (void) sock_err(sp->asyncerr);
  683.             sp->asyncerr = 0;
  684.             return(-1);
  685.         }
  686.  
  687.         /* I guess he just forgot */
  688.         return(sock_err(ENOTCONN));        
  689.     }
  690.     
  691.     /* is there a free write pb */
  692.     if (sp->wpb[sp->nextwpb].pb.tcp.ioResult == inProgress)
  693.     {
  694.         /* no there isn't */
  695.         if (sp->nonblocking)
  696.             return(sock_err(EWOULDBLOCK));
  697.         
  698. #if SOCK_TCP_DEBUG >= 5
  699.         dprintf("sock_tcp_send: spinning for free wpb\n");
  700. #endif
  701.         while(sp->wpb[sp->nextwpb].pb.tcp.ioResult == inProgress)
  702.         {
  703. #if SOCK_TCP_DEBUG >= 5
  704.             tcpCheckNotify();
  705. #endif
  706.             if (spinroutine != NULL)
  707.                 (*spinroutine)();
  708.         }
  709. #if SOCK_TCP_DEBUG >= 5
  710.         dprintf("sock_tcp_send: done spinning\n");
  711. #endif
  712.     
  713.         /* make sure the thing that just finished worked ok */
  714.         if (sp->asyncerr != 0)
  715.         {
  716.             (void) sock_err(sp->asyncerr);
  717.             sp->asyncerr = 0;
  718.             return(-1);
  719.         }
  720.     }
  721.     
  722.     /* copy the caller's data into the wds in the write pb */
  723.     if (! vector)
  724.         bytes = sock_buf_to_wds(sp, buffer, count);
  725.     else
  726.         bytes = sock_iov_to_wds(sp, (struct iovec *)buffer, count);
  727.     if (bytes < 0)
  728.         return(-1); /* errno set */
  729.  
  730. #if (SOCK_TCP_DEBUG >= 7) || defined(TCP_PACKET_TRACE)
  731.  
  732. #ifdef 0
  733.     hex_dump(sp->wpb[sp->nextwpb].wds[0].ptr, sp->wpb[sp->nextwpb].wds[0].length,
  734.             "tcp to %08x/%d\n",
  735.             sp->peer.sin_addr.s_addr,
  736.             sp->peer.sin_port);
  737. #endif
  738.  
  739. #endif
  740.     
  741.     /* and finally .... */
  742.     io = xTCPSend(&sp->wpb[sp->nextwpb].pb.tcp, 
  743.                   &sp->wpb[sp->nextwpb].wds[0],
  744.                   true/*push*/, 
  745.                   false/*urgent*/, 
  746.                   sock_tcp_send_done);
  747.     if (io != noErr)
  748.         return(sock_err(io));
  749.     
  750.     sp->nextwpb = (sp->nextwpb+1) % TCP_MAX_WRITES;
  751.  
  752.     return(bytes);
  753. }
  754.  
  755. static void
  756. sock_tcp_send_done(wpb)
  757.     write_pb *wpb;
  758. {
  759.     SocketPtr sp = wpb->sp;
  760.  
  761.     switch(wpb->pb.tcp.ioResult)
  762.     {
  763.         case noErr: 
  764.             break;
  765.             
  766.         case ipNoFragMemErr:
  767.         case connectionClosing:
  768.         case connectionTerminated:
  769.         case connectionDoesntExist:
  770.             sp->sstate = SOCK_STATE_UNCONNECTED;
  771.             sp->asyncerr = ENOTCONN;
  772.             break;
  773.             
  774.         case ipDontFragErr:
  775.         case invalidStreamPtr:
  776.         case invalidLength:
  777.         case invalidWDS:
  778.         default:
  779.             sp->sstate = SOCK_STATE_UNCONNECTED;
  780.             sp->asyncerr = wpb->pb.tcp.ioResult;
  781.             break;
  782.     }
  783. }
  784.  
  785.  
  786. /*
  787.  *    sock_tcp_can_write() - returns non-zero if a write will not block
  788.  */
  789. sock_tcp_can_write(sp)
  790.     SocketPtr sp;
  791. {
  792.     if (sp->sstate == SOCK_STATE_CONNECTED)
  793.         if (sp->wpb[sp->nextwpb].pb.tcp.ioResult != inProgress)
  794.             return(1);
  795.     return(0);
  796. }
  797.  
  798. /*
  799.  *    sock_tcp_close() - close down a socket being careful about i/o in progress
  800.  */
  801. sock_tcp_close(sp)
  802.     SocketPtr sp;
  803. {
  804.     OSErr io;
  805.     
  806. #if SOCK_TCP_DEBUG >= 2
  807.     sock_print("sock_tcp_close %08x",sp);
  808. #endif
  809.  
  810.     /* close the stream */ 
  811.     io = xTCPClose(&sp->pb.tcp,-1);
  812. #if SOCK_TCP_DEBUG >= 5
  813.     dprintf("sock_tcp_close: xTCPClose returns %d\n",io);
  814. #endif
  815.     switch (io)
  816.     {
  817.         case noErr:
  818.             break;
  819.         case connectionClosing:
  820.             io = noErr;
  821.             break;
  822.         case connectionDoesntExist:
  823.         case connectionTerminated:
  824.             break;
  825.         case invalidStreamPtr:
  826.         default:
  827.             return(sock_err(io));
  828.     }
  829.  
  830.     /* wait for any writes in progress to finish if necessary */ 
  831. #if SOCK_TCP_DEBUG >= 5
  832.     dprintf("sock_tcp_close: spinning\n");
  833. #endif
  834.     if (io == noErr)
  835.     {
  836.         while (sp->pb.tcp.ioResult == inProgress)
  837.         {
  838.             /* can we wait? */
  839.             if (sp->nonblocking)
  840.                 return(sock_err(EWOULDBLOCK));
  841.             
  842. #if SOCK_TCP_DEBUG >= 5
  843.             tcpCheckNotify();
  844. #endif
  845.             if (spinroutine != NULL)
  846.                 (*spinroutine)();
  847.         }
  848.     }
  849. #if SOCK_TCP_DEBUG >= 5
  850.     dprintf("sock_tcp_close: done spinning\n");
  851. #endif
  852.  
  853.     /* destroy the stream */ 
  854.     if ((io = xTCPRelease(&sp->pb.tcp)) != noErr)
  855.     {
  856. #if SOCK_TCP_DEBUG >= 5
  857.         dprintf("sock_tcp_close: xTCPRelease error %d\n",io);
  858. #endif
  859.         return(sock_err(io));
  860.     }
  861.     /* check for errors from async writes etc */
  862.     if (sp->asyncerr != 0)
  863.     {
  864. #if SOCK_TCP_DEBUG >= 5
  865.         dprintf("sock_tcp_close: asyncerr %d\n",sp->asyncerr);
  866. #endif
  867.         return(sock_err(sp->asyncerr));
  868.     }
  869.     return(0);
  870. }
  871.  
  872.